package com.example.chatapplication;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.le.AdvertiseData;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {

    Button btlisten, btsend, btlistDevices;
    ListView listView;
    TextView msg_box, status;
    EditText writeMsg;

    BluetoothAdapter bluetoothAdapter;
    BluetoothDevice[] btDevice;

    SendReceive sendReceive;

    static final int STATE_LISTNING = 1;
    static final int STATE_CONNECTING = 2;
    static final int STATE_CONNECTED = 3;
    static final int STATE_CONNECTION_FAILED = 4;
    static final int STATE_MESSAGE_RECEIVED =5;

    private static final String TAG = "chatApplication";
    private static final String APP_NAME = "BTChat";
    private static final UUID mUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    int REQUEST_ENABLE_OK =1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btlisten = findViewById(R.id.btlisten);
        btsend = findViewById(R.id.btsend);
        btlistDevices = findViewById(R.id.btlistDevices);
        listView = findViewById(R.id.listview);
        msg_box = findViewById(R.id.msg_box);
        status = findViewById(R.id.status);
        writeMsg = findViewById(R.id.writeMsg);
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        if (!bluetoothAdapter.isEnabled())
        {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_OK);
        }

        implementListeners();


    }

    private void implementListeners() {

        btlistDevices.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
                String[] strings = new String[pairedDevices.size()];
                btDevice = new BluetoothDevice[pairedDevices.size()];
                int index = 0;

                if (pairedDevices.size() > 0)
                {
                    for (BluetoothDevice device : pairedDevices)
                    {
                        btDevice[index] = device;
                        strings[index] = device.getName() + " @ " + device.getAddress();
                        index ++;

                    }

                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, strings);
                    listView.setAdapter(arrayAdapter);

                }
            }
        });

        btlisten.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                ServerClass serverClass = new ServerClass();
                serverClass.start();
            }
        });

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int i, long id) {
                 ClientClass clientClass = new ClientClass(btDevice[i]);
                 clientClass.start();

                 status.setText("Connecting");
            }
        });
        btsend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String string = String.valueOf(writeMsg.getText());
                sendReceive.write(string.getBytes());

            }
        });
    }


//    private AdapterView.OnItemClickListener bondedDeviceList = new AdapterView.OnItemClickListener() {
//        @Override
//        public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
//            ClientClass clientClass = new ClientClass(btDevice[position]);
//            clientClass.start();
//        }
//    };

    Handler handler = new Handler(new Handler.Callback() {
        @SuppressLint("SetTextI18n")
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what)
            {
                case STATE_LISTNING:
                    status.setText("Listening");
                    break;
                case STATE_CONNECTING:
                    status.setText("Connecting");
                    break;
                case STATE_CONNECTED:
                    status.setText("Connected");
                    break;
                case STATE_CONNECTION_FAILED:
                    status.setText("Connection Failed");
                    break;
                case STATE_MESSAGE_RECEIVED:
                    byte[] readBuffer = (byte[]) msg.obj;
                    String tempMsg = new String(readBuffer, 0, msg.arg1);
                    msg_box.setText(tempMsg);
                    break;
            }
            return true;
        }
    });


    private class ClientClass extends Thread
    {
        private final BluetoothDevice mdevice;
        private BluetoothSocket socket = null;

        private ClientClass(BluetoothDevice  device) {
            this.mdevice = device;

        //用BluetoothSocket连接到给定的蓝牙设备
            try {
                socket = device.createRfcommSocketToServiceRecord(mUUID);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        public void run()
        {
           bluetoothAdapter.cancelDiscovery();
            try {
                socket.connect();
                Message message = Message.obtain();
                message.what = STATE_CONNECTED;
                handler.sendMessage(message);

                sendReceive = new SendReceive(socket);
                sendReceive.start();

            } catch (IOException e) {
                e.printStackTrace();
                handler.sendMessage(handler.obtainMessage(STATE_CONNECTION_FAILED));
            }

        }
    }

    private class ServerClass extends Thread
    {
        private BluetoothServerSocket serverSocket;
        public ServerClass()
        {
            BluetoothServerSocket tmp =null;
            try {
                tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(APP_NAME, mUUID);

                Log.d(TAG, "ServerClass: Setting up a Server using" + mUUID);
            } catch (IOException e) {
                e.printStackTrace();
            }

            serverSocket = tmp;
        }

        public void run()
        {
            Log.d(TAG, "run: ServerClass");

            BluetoothSocket socket = null;

            Log.d(TAG, "run: RFCOM servers socket start ......");

            while (socket == null)
            {
                try {
//                    Message message = Message.obtain();
//                    message.what = STATE_LISTNING;
//                    handler.sendMessage(message);
                    handler.sendMessage(handler.obtainMessage(STATE_LISTNING));
                    socket = serverSocket.accept();

                    Log.d(TAG, "run: RFCOM server socket accepted connection");
                } catch (IOException e) {
                    e.printStackTrace();
                    handler.sendMessage(handler.obtainMessage(STATE_CONNECTION_FAILED));
//                    Message message = Message.obtain();
//                    message.what = STATE_CONNECTION_FAILED;
//                    handler.sendMessage(message);
                }

                if (socket !=null)
                {
                    handler.sendMessage(handler.obtainMessage(STATE_CONNECTED));

                    sendReceive = new SendReceive(socket);
                    sendReceive.start();


                    break;
                }
            }
        }

        private void cancle()
        {
            Log.d(TAG, "cancel: Canceling Server");

            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private class SendReceive extends Thread
    {
        private final BluetoothSocket bluetoothSocket;
        private final InputStream inputStream ;
        private final OutputStream outputStream ;

        private SendReceive(BluetoothSocket socket) {
            bluetoothSocket = socket;
            InputStream tempIn = null;
            OutputStream tempOut = null;
            // 使用临时对象获取输入和输出流，因为成员流是最终的
            try {
                tempIn = bluetoothSocket.getInputStream();
                tempOut = bluetoothSocket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }

            inputStream = tempIn;
            outputStream = tempOut;
        }

        public void run()
        {
            byte[] buffer = new byte[1024];
            // 从read()返回bytes
            int bytes;

            while (true) {
                try {

                    bytes = inputStream.read(buffer);
                    // 从InputStream读取数据
                    if (bytes > 0) {

//                      Message message = handler.obtainMessage(STATE_MESSAGE_RECEIVED, new String(buffer, 0, bytes, "utf-8"));
//                      handler.sendMessage(message);
                        handler.obtainMessage(STATE_MESSAGE_RECEIVED, bytes, -1, buffer).sendToTarget();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        private void write(byte[] bytes)
        {
            try {
                outputStream.write(bytes);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
